home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / DB.C < prev    next >
C/C++ Source or Header  |  1989-12-29  |  11KB  |  548 lines

  1. /*
  2.  * database access and update
  3.  */
  4.  
  5. #include "config.h"
  6. #include "db.h"
  7.  
  8. export master_header master;
  9. export group_header *active_groups, **sorted_groups;
  10.  
  11. /*
  12.  * Init access to a group
  13.  */
  14.  
  15. export group_header *current_group = NULL;
  16.  
  17. export char    group_path_name[FILENAME];
  18. export char    *group_file_name = NULL;
  19.  
  20. static    char    *group_position = NULL;
  21.  
  22. init_group(gh)
  23. register group_header *gh;
  24. {
  25.     register    char    *p, *q;
  26.  
  27.     if (gh == NULL) return 0;
  28.     if (gh == current_group) return 1;
  29.     
  30.     current_group = gh;
  31.  
  32.     if (gh->group_flag & G_FOLDER) {
  33.     group_position = NULL;
  34.     group_file_name = NULL;
  35.     strcpy(group_path_name, gh->group_name);
  36.     return 1;
  37.     }
  38.  
  39. #ifdef NNTP
  40.     if (use_nntp && nntp_set_group(gh) < 0)
  41.     return 0;
  42. #endif /* NNTP */
  43.  
  44.     if (group_position == NULL)
  45.     if (is_master) 
  46.         group_position = group_path_name;
  47.     else {
  48.         strcpy(group_path_name, news_directory);
  49.         group_position = group_path_name + strlen(group_path_name);
  50.         *group_position++ = '/';
  51.     }
  52.     
  53.     for (p = group_position, q = gh->group_name; *q; q++)
  54.     *p++ = (*q == '.') ? '/' : *q;
  55.  
  56.     if (is_master) {
  57.  
  58.     /*
  59.      *    The master will chdir to the group's directory to
  60.      *    get better performance (can use relative path names).
  61.      *
  62.      *    We cannot do the same for the user client, because of
  63.      *    the 'save' commands.
  64.      */
  65.  
  66.     *p++ = NUL;
  67.     
  68. #ifdef NNTP
  69.     if (!use_nntp) {
  70. #endif
  71.         if (chdir(news_directory) < 0)
  72.         sys_error(news_directory);
  73.         
  74.         if (chdir(group_path_name) < 0)
  75.         return 0;
  76. #ifdef NNTP
  77.     }
  78. #endif /* NNTP */
  79.  
  80.     group_file_name = group_path_name;
  81.  
  82.     } else {
  83.  
  84.     /* client */
  85.     if (gh->group_flag & G_NO_DIRECTORY) return 0;
  86.  
  87.     *p++ = '/';
  88.     group_file_name = p;
  89.     }
  90.  
  91.     return 1;
  92. }
  93.  
  94.  
  95. FILE *open_groups(mode)
  96. {
  97.     return open_file(relative(db_directory, "GROUPS"), mode);
  98. }
  99.  
  100.     
  101.  
  102. /*
  103.  *    Open master file; read it in if first open.
  104.  */
  105.  
  106. FILE *master_file = NULL;
  107.  
  108. open_master(mode)
  109. {
  110.     FILE             *g;
  111.     int             n, cur_group;
  112.     unsigned            entries;
  113.     char             *strings;
  114.     register group_header     *gh;
  115.     static int             first_open = 1;
  116.     
  117.     
  118.     master_file = open_file(relative(db_directory, "MASTER"), mode|MUST_EXIST);
  119.  
  120.     if (mode == OPEN_CREATE || !first_open) return;
  121.     
  122.     first_open = 0;
  123.     
  124.     if (!db_read_master(master_file, &master))
  125.     sys_error("Incomplete MASTER");
  126.     
  127.     master.free_groups = master.number_of_groups / 10;
  128.     
  129.     entries = master.free_groups + master.number_of_groups;
  130.     
  131.     active_groups = (group_header *) calloc(entries, sizeof(group_header));
  132.     mem_check(active_groups, entries, "group headers");
  133.     
  134.     sorted_groups = (group_header **) 
  135.     calloc(entries, sizeof(group_header *));
  136.     mem_check((char *)sorted_groups, entries, "sorted group header pointers");
  137.  
  138.     strings = malloc((unsigned)master.next_group_write_offset);
  139.     mem_check(strings, (int)master.next_group_write_offset, 
  140.           "bytes for group names");
  141.  
  142.     g = open_groups(OPEN_READ|MUST_EXIST);
  143.  
  144.     n = fread(strings, sizeof(char), (int)master.next_group_write_offset, g);
  145.     if (n != (int)master.next_group_write_offset)
  146.     sys_error("Incomplete GROUPS file");
  147.     fclose(g);
  148.     
  149.     for (cur_group = 0, gh = active_groups;
  150.      cur_group < master.number_of_groups;
  151.      cur_group++, gh++) {
  152.  
  153.     sorted_groups[cur_group] = gh;
  154.     
  155.     if (!db_read_group(master_file, gh, -1))
  156.         sys_error("Incomplete MASTER file");
  157.     
  158.     gh->group_num = cur_group;
  159.     gh->group_name = strings;
  160.     strings += gh->group_name_length;
  161.     *strings++ = NUL;
  162.     }    
  163.  
  164.     sort_groups();
  165. }
  166.  
  167.  
  168. close_master()
  169. {
  170.     if (master_file != NULL) {
  171.     fclose(master_file);
  172.     master_file = NULL;
  173.     }
  174. }
  175.  
  176.  
  177. update_group(gh)
  178. group_header *gh;
  179. {
  180.     int32 flag;
  181.  
  182.     flag = gh->group_flag & ~G_MASTER_FLAGS;
  183.  
  184.     if (!db_read_group(master_file, gh, gh->group_num)) return -1;
  185.     
  186.     gh->group_flag |= flag;
  187.  
  188.     if (gh->group_flag & G_BLOCKED) return -1;
  189.     
  190.     return 1;
  191. }
  192.  
  193.     
  194. static group_name_cmp(g1, g2)
  195. group_header **g1, **g2;
  196. {
  197.     return strcmp((*g1)->group_name, (*g2)->group_name);
  198. }
  199.  
  200.  
  201. sort_groups()
  202. {
  203.     qsort((char *)sorted_groups, (unsigned)master.number_of_groups,
  204.       sizeof(group_header *), group_name_cmp);
  205. }
  206.  
  207.  
  208. group_header *lookup(name)
  209. char *name;
  210. {
  211.     register i, j, k, t;
  212.     
  213.     i = 0; j = master.number_of_groups - 1; 
  214.     
  215.     while (i <= j) {
  216.     k = (i + j) / 2;
  217.  
  218.     if ( (t=strcmp(name, sorted_groups[k]->group_name)) > 0) 
  219.         i = k+1;
  220.     else
  221.     if (t < 0)
  222.         j = k-1;
  223.     else
  224.         return sorted_groups[k];
  225.     }
  226.     
  227.     return NULL;
  228. }
  229.  
  230.  
  231. art_collected(gh, art_num)
  232. group_header *gh;
  233. article_number art_num;
  234. {
  235.     return gh->first_l_article <= art_num && gh->last_l_article >= art_num;
  236. }
  237.  
  238.  
  239. FILE *open_data_file(gh, d_or_x, mode)
  240. group_header *gh;
  241. char d_or_x;
  242. int mode;
  243. {
  244.     char data_file[FILENAME];
  245.     
  246.     sprintf(data_file, "%s/DATA/%d.%c", db_directory, gh->group_num, d_or_x);
  247.  
  248.     if (mode == -1) {
  249.     unlink(data_file);
  250.     return (FILE *)NULL;
  251.     } else
  252.     return open_file(data_file, mode);
  253. }
  254.  
  255.  
  256. #ifdef NETWORK_DATABASE
  257.  
  258. #define MASTER_FIELDS    3
  259. #define    GROUP_FIELDS    6
  260. #define    ARTICLE_FIELDS    10
  261.  
  262.  
  263. typedef int32 net_long;
  264.  
  265.  
  266. #ifdef NETWORK_BYTE_ORDER
  267.  
  268. #define net_to_host(buf, n)
  269. #define host_to_net(buf, n)
  270.  
  271. #else
  272.  
  273. static net_to_host(buf, lgt)
  274. register net_long *buf;
  275. int lgt;
  276. {
  277.     while (--lgt >= 0) {
  278.     *buf = ntohl(*buf);
  279.     buf++;
  280.     }
  281. }
  282.  
  283. static host_to_net(buf, lgt)
  284. register net_long *buf;
  285. int lgt;
  286. {
  287.     while (--lgt >= 0) {
  288.     *buf = htonl(*buf);
  289.     buf++;
  290.     }
  291. }
  292. #endif /* not NETWORK_BYTE_ORDER */
  293. #endif /* NETWORK_DATABASE */
  294.  
  295.  
  296. db_read_master(f, masterp)
  297. FILE *f;
  298. master_header *masterp;  
  299. {
  300. #ifdef NETWORK_DATABASE
  301.     net_long buf[MASTER_FIELDS];
  302.     
  303.     if (fread(buf, sizeof(net_long), MASTER_FIELDS, f) != MASTER_FIELDS)
  304.     return 0;
  305.  
  306.     net_to_host(buf, MASTER_FIELDS);
  307.     
  308.     masterp->last_scan = buf[0];
  309.     masterp->number_of_groups = buf[1];
  310.     masterp->next_group_write_offset = buf[2];
  311. #else
  312.  
  313.     if (fread(masterp, sizeof(master_header), 1, f) != 1) return 0;
  314. #endif
  315.     return 1;
  316. }
  317.  
  318.  
  319. db_write_master(f, masterp)
  320. FILE *f;
  321. master_header *masterp;  
  322. {
  323. #ifdef NETWORK_DATABASE
  324.     net_long buf[MASTER_FIELDS];
  325.     
  326.     buf[0] = masterp->last_scan;
  327.     buf[1] = masterp->number_of_groups;
  328.     buf[2] = masterp->next_group_write_offset;
  329.  
  330.     host_to_net(buf, MASTER_FIELDS);
  331.     if (fwrite(buf, sizeof(net_long), MASTER_FIELDS, f) != MASTER_FIELDS) return 0;
  332. #else
  333.  
  334.     if (fwrite((char *)masterp, sizeof(master_header), 1, f) != 1) return 0;
  335. #endif
  336.     return 1;
  337. }
  338.  
  339. db_read_group(f, gh, n)
  340. FILE *f;
  341. register group_header *gh;
  342. group_number n;
  343. {
  344. #ifdef NETWORK_DATABASE
  345.     net_long buf[GROUP_FIELDS];
  346.  
  347.     if (n >= 0) 
  348.     fseek(f, MASTER_FIELDS * sizeof(net_long) + GROUP_FIELDS * sizeof(net_long) * n, 0);
  349.  
  350.     if (fread(buf, sizeof(net_long), GROUP_FIELDS, f) != GROUP_FIELDS)
  351.     return 0;
  352.  
  353.     net_to_host(buf, GROUP_FIELDS);
  354.  
  355.     gh->first_l_article = buf[0];
  356.     gh->last_l_article = buf[1];
  357.     gh->index_write_offset = buf[2];
  358.     gh->data_write_offset = buf[3];
  359.     gh->group_name_length = buf[4];
  360.     gh->group_flag = buf[5];
  361. #else
  362.     
  363.     if (n >= 0)
  364.     fseek(f, (off_t)(sizeof(master_header) + SAVED_GROUP_HEADER_SIZE(*gh) * n), 0);
  365.  
  366.     if (fread(gh, SAVED_GROUP_HEADER_SIZE(*gh), 1, f) != 1)
  367.     return 0;
  368.  
  369. #endif
  370.     return 1;
  371. }
  372.  
  373.  
  374. db_write_group(f, gh, n)
  375. FILE *f;
  376. register group_header *gh;
  377. group_number n;
  378. {
  379. #ifdef NETWORK_DATABASE
  380.     net_long buf[GROUP_FIELDS];
  381.  
  382.     if (n >= 0) 
  383.     fseek(f, MASTER_FIELDS * sizeof(net_long) + GROUP_FIELDS * sizeof(net_long) * n, 0);
  384.  
  385.     buf[0] = gh->first_l_article;
  386.     buf[1] = gh->last_l_article;
  387.     buf[2] = gh->index_write_offset;
  388.     buf[3] = gh->data_write_offset;
  389.     buf[4] = gh->group_name_length;
  390.     buf[5] = gh->group_flag;
  391.  
  392.     host_to_net(buf, GROUP_FIELDS);
  393.     if (fwrite(buf, sizeof(net_long), GROUP_FIELDS, f) != GROUP_FIELDS)
  394.     return 0;
  395.  
  396. #else
  397.     if (n >= 0)
  398.     fseek(f, (off_t)(sizeof(master_header) + SAVED_GROUP_HEADER_SIZE(*gh) * n), 0);
  399.  
  400.     if (fwrite((char *)gh, SAVED_GROUP_HEADER_SIZE(*gh), 1, f) != 1)
  401.     return 0;
  402. #endif
  403.  
  404.     return 1;
  405. }
  406.  
  407.  
  408. db_read_art(f, dh, offset)
  409. FILE *f;
  410. data_header *dh;
  411. off_t *offset;
  412. {
  413. #ifdef NETWORK_DATABASE
  414.     net_long buf[ARTICLE_FIELDS];
  415.     
  416.     if (fread(buf, sizeof(net_long), ARTICLE_FIELDS, f) != ARTICLE_FIELDS)
  417.     return 0;
  418.     
  419.     net_to_host(buf, ARTICLE_FIELDS);
  420.  
  421.     dh->dh_number = buf[0];
  422.     dh->dh_date = buf[1];
  423.     dh->dh_hpos = buf[2];
  424.     dh->dh_lpos = buf[3];
  425.     dh->dh_fpos = buf[4];
  426.     dh->dh_lines = buf[5];
  427.     dh->dh_replies = buf[6];
  428.     dh->dh_cross_postings = buf[7];
  429.     dh->dh_subject_length = buf[8];
  430.     dh->dh_sender_length = buf[9];
  431.  
  432.     if (offset) *offset += ARTICLE_FIELDS * sizeof(net_long);
  433. #else
  434.     
  435.     if (fread((char *)dh, sizeof(data_header), 1, f) != 1) return 0;
  436.     if (offset) *offset += sizeof(data_header);
  437. #endif
  438.     return 1;
  439. }
  440.  
  441. db_write_art(f, dh)
  442. FILE *f;
  443. data_header *dh;
  444. {
  445. #ifdef NETWORK_DATABASE
  446.     net_long buf[ARTICLE_FIELDS];
  447.  
  448.     buf[0] = dh->dh_number;
  449.     buf[1] = dh->dh_date;
  450.     buf[2] = dh->dh_hpos;
  451.     buf[3] = dh->dh_lpos;
  452.     buf[4] = dh->dh_fpos;
  453.     buf[5] = dh->dh_lines;
  454.     buf[6] = dh->dh_replies;
  455.     buf[7] = dh->dh_cross_postings;
  456.     buf[8] = dh->dh_subject_length;
  457.     buf[9] = dh->dh_sender_length;
  458.  
  459.     host_to_net(buf, ARTICLE_FIELDS);
  460.  
  461.     if (fwrite(buf, sizeof(net_long), ARTICLE_FIELDS, f) != ARTICLE_FIELDS)
  462.     return 0;
  463. #else
  464.     
  465.     if (fwrite((char *)dh, sizeof(data_header), 1, f) != 1) return 0;
  466.  
  467. #endif
  468.  
  469.     return 1;
  470. }
  471.  
  472.  
  473.  
  474. off_t get_index_offset(gh, art_num)
  475. group_header *gh;
  476. article_number art_num;
  477. {
  478. #ifdef NETWORK_DATABASE
  479.     return (off_t)((art_num - gh->first_l_article) * sizeof(net_long));
  480. #else
  481.     return (off_t)((art_num - gh->first_l_article) * sizeof(off_t));
  482. #endif
  483. }
  484.  
  485. off_t get_data_offset(gh, art_num)
  486. group_header *gh;
  487. article_number art_num;
  488. {
  489.     FILE *index;
  490.     off_t data_offset;
  491.     
  492.     if (gh->first_l_article == art_num) return (off_t)0;
  493.     
  494.     index = open_data_file(gh, 'x', OPEN_READ);
  495.     if (index == NULL) return (off_t)(-1);
  496.     
  497.     fseek(index, get_index_offset(gh, art_num), 0);
  498.     if (!db_read_offset(index, &data_offset))
  499.     return (off_t)(-1);
  500.  
  501.     fclose(index);
  502.     
  503.     return data_offset;
  504. }
  505.  
  506.  
  507. db_read_offset(f, offset)
  508. FILE *f;
  509. off_t *offset;
  510. {
  511. #ifdef NETWORK_DATABASE
  512.     net_long temp;
  513.  
  514.     if (fread(&temp, sizeof(net_long), 1, f) != 1) return 0;
  515.  
  516. #ifndef NETWORK_BYTE_ORDER
  517.     temp = ntohl(temp);
  518. #endif
  519.     *offset = temp;
  520. #else    
  521.  
  522.     if (fread((char *)offset, sizeof(off_t), 1, f) != 1) return 0;
  523. #endif
  524.     return 1;
  525. }
  526.  
  527. db_write_offset(f, offset)
  528. FILE *f;
  529. off_t *offset;
  530. {
  531. #ifdef NETWORK_DATABASE
  532.     net_long temp;
  533.  
  534.     temp = *offset;
  535.  
  536. #ifndef NETWORK_BYTE_ORDER
  537.     temp = htonl(temp);
  538. #endif
  539.     if (fwrite(&temp, sizeof(net_long), 1, f) != 1) return 0;
  540.  
  541. #else    
  542.  
  543.     if (fwrite((char *)offset, sizeof(off_t), 1, f) != 1) return 0;
  544. #endif
  545.     return 1;
  546. }
  547.  
  548.